package com.zndroid.gridview;

import android.animation.Animator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;

import com.zndroid.gridview.inner.ScreenUtil;
import com.zndroid.gridview.load.IImageDisplayEngine;
import com.zndroid.gridview.preview.ImageAttribute;
import com.zndroid.gridview.preview.ImagePreviewAdapter;
import com.zndroid.gridview.preview.indicator.IIndicator;
import com.zndroid.gridview.preview.indicator.impl.TextViewBgIndicator;

import java.io.Serializable;
import java.util.Collections;
import java.util.List;

/**
 * @author lzy
 */
public class ImagePreviewActivity extends AppCompatActivity implements ViewTreeObserver.OnPreDrawListener {
    public static final String CURRENT_ITEM = "CURRENT_ITEM";
    public static final String IMAGE_ATTRIBUTE = "IMAGE_ATTRIBUTE";
    public static final int ANIMATE_DURATION = 200;

    private static IImageDisplayEngine engine;
    private static IIndicator indicator;

    private RelativeLayout rootView;

    private ImagePreviewAdapter imagePreviewAdapter;
    private List<ImageAttribute> imageAttributes;
    private int currentItem;
    private int imageHeight;
    private int imageWidth;
    private int screenWidth;
    private int screenHeight;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_gil_preview);

        new ScreenUtil().transparentStatusBar(this);

        init();
    }

    public static void toPreview(Context context, IImageDisplayEngine engine, List<ImageAttribute> imageAttributes, int index) {
        ImagePreviewActivity.engine = engine;
        ImagePreviewActivity.indicator = new TextViewBgIndicator();

        Intent intent = new Intent(context, ImagePreviewActivity.class);
        Bundle bundle = new Bundle();
        bundle.putSerializable(ImagePreviewActivity.IMAGE_ATTRIBUTE, (Serializable) imageAttributes);
        bundle.putInt(ImagePreviewActivity.CURRENT_ITEM, index);
        intent.putExtras(bundle);
        context.startActivity(intent);

        //去掉自带的动画效果
        ((Activity) context).overridePendingTransition(0, 0);
    }

    public static void toPreview(Context context, IIndicator indicator, IImageDisplayEngine engine, List<ImageAttribute> imageAttributes, int index) {
        ImagePreviewActivity.engine = engine;
        ImagePreviewActivity.indicator = indicator;

        Intent intent = new Intent(context, ImagePreviewActivity.class);
        Bundle bundle = new Bundle();
        bundle.putSerializable(ImagePreviewActivity.IMAGE_ATTRIBUTE, (Serializable) imageAttributes);
        bundle.putInt(ImagePreviewActivity.CURRENT_ITEM, index);
        intent.putExtras(bundle);
        context.startActivity(intent);

        //去掉自带的动画效果
        ((Activity) context).overridePendingTransition(0, 0);
    }

    private void init() {
        ScreenUtil screenUtil = new ScreenUtil();

        ViewPager viewPager = (ViewPager) findViewById(R.id.vp_gil_preview);
        rootView = (RelativeLayout) findViewById(R.id.rootView);

        View indicatorView = indicator.bindView(getLayoutInflater(), rootView);

        if (null != indicatorView) {
            RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
            switch (indicator.gravity()) {
                case IIndicator.CENTER:
                    layoutParams.addRule(RelativeLayout.CENTER_IN_PARENT);
                    break;
                case IIndicator.CENTER_RIGHT:
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
                    layoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
                    break;
                case IIndicator.RIGHT_TOP:
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
                    break;
                case IIndicator.CENTER_TOP:
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
                    layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
                    break;
                case IIndicator.LEFT_TOP:
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
                    break;
                case IIndicator.CENTER_LEFT:
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
                    layoutParams.addRule(RelativeLayout.CENTER_VERTICAL);
                    break;
                case IIndicator.LEFT_BOTTOM:
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
                    break;
                case IIndicator.CENTER_BOTTOM:
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
                    layoutParams.addRule(RelativeLayout.CENTER_HORIZONTAL);
                    break;
                case IIndicator.RIGHT_BOTTOM:
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
                    layoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
                    break;
                default:
                    break;
            }

            layoutParams.setMargins(
                    screenUtil.dp2px(this, indicator.left()),
                    screenUtil.dp2px(this, indicator.top()),
                    screenUtil.dp2px(this, indicator.right()),
                    screenUtil.dp2px(this, indicator.bottom()));
            rootView.addView(indicatorView, layoutParams);
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
            screenWidth = getWindowManager().getCurrentWindowMetrics().getBounds().width();
            screenHeight = getWindowManager().getCurrentWindowMetrics().getBounds().height();
        } else {
            DisplayMetrics metric = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(metric);

            screenWidth = metric.widthPixels;
            screenHeight = metric.heightPixels;
        }

        Intent intent = getIntent();
        imageAttributes = Collections.unmodifiableList((List<ImageAttribute>) intent.getSerializableExtra(IMAGE_ATTRIBUTE));
        currentItem = intent.getIntExtra(CURRENT_ITEM, 0);

        imagePreviewAdapter = new ImagePreviewAdapter(this, imageAttributes, engine);
        imagePreviewAdapter.setCallBack(this::finishActivityAnim);

        viewPager.setAdapter(imagePreviewAdapter);
        viewPager.setCurrentItem(currentItem);
        viewPager.getViewTreeObserver().addOnPreDrawListener(this);
        viewPager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
            @Override
            public void onPageSelected(int position) {
                currentItem = position;
                if (null != indicator) {
                    indicator.onIndex(indicatorView, currentItem, imageAttributes.size());
                }
            }
        });

        if (null != indicator) {
            indicator.onIndex(indicatorView, currentItem, imageAttributes.size());
        }
    }

    @Override
    public boolean onPreDraw() {
        rootView.getViewTreeObserver().removeOnPreDrawListener(this);
        final View view = imagePreviewAdapter.getPrimaryItem();
        final ImageView imageView = imagePreviewAdapter.getPrimaryImageView();
        computeImageWidthAndHeight(imageView);

        final ImageAttribute imageAttribute = imageAttributes.get(currentItem);

        final int[] w_h_x_y = imageAttribute.getWhxy();

        int imageViewWidth = w_h_x_y[0];
        int imageViewHeight = w_h_x_y[1];
        int imageViewX = w_h_x_y[2];
        int imageViewY = w_h_x_y[3];

        final float vx = imageViewWidth * 1.0f / imageWidth;
        final float vy = imageViewHeight * 1.0f / imageHeight;
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1.0f);
        valueAnimator.addUpdateListener(animation -> {
            long duration = animation.getDuration();
            long playTime = animation.getCurrentPlayTime();
            float fraction = duration > 0 ? (float) playTime / duration : 1f;
            if (fraction > 1) {
                fraction = 1;
            }
            view.setTranslationX(evaluateInt(fraction, imageViewX + imageViewWidth / 2 - imageView.getWidth() / 2, 0));
            view.setTranslationY(evaluateInt(fraction, imageViewY + imageViewHeight / 2 - imageView.getHeight() / 2, 0));
            view.setScaleX(evaluateFloat(fraction, vx, 1));
            view.setScaleY(evaluateFloat(fraction, vy, 1));
            view.setAlpha(fraction);
            rootView.setBackgroundColor(evaluateArgb(fraction, Color.TRANSPARENT, Color.BLACK));
        });
        addIntoListener(valueAnimator);
        valueAnimator.setDuration(ANIMATE_DURATION);
        valueAnimator.start();
        return true;
    }

    @Override
    public void onBackPressed() {
        finishActivityAnim();
    }

    /** activity的退场动画 */
    public void finishActivityAnim() {
        final View view = imagePreviewAdapter.getPrimaryItem();
        final ImageView imageView = imagePreviewAdapter.getPrimaryImageView();
        computeImageWidthAndHeight(imageView);

        final ImageAttribute imageAttribute = imageAttributes.get(currentItem);
        final int[] w_h_x_y = imageAttribute.getWhxy();

        int imageViewWidth = w_h_x_y[0];
        int imageViewHeight = w_h_x_y[1];
        int imageViewX = w_h_x_y[2];
        int imageViewY = w_h_x_y[3];

        final float vx = imageViewWidth * 1.0f / imageWidth;
        final float vy = imageViewHeight * 1.0f / imageHeight;
        final ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1.0f);
        valueAnimator.addUpdateListener(animation -> {
            long duration = animation.getDuration();
            long playTime = animation.getCurrentPlayTime();
            float fraction = duration > 0 ? (float) playTime / duration : 1f;
            if (fraction > 1) {
                fraction = 1;
            }
            view.setTranslationX(evaluateInt(fraction, 0, imageViewX + imageViewWidth / 2 - imageView.getWidth() / 2));
            view.setTranslationY(evaluateInt(fraction, 0, imageViewY + imageViewHeight / 2 - imageView.getHeight() / 2));
            view.setScaleX(evaluateFloat(fraction, 1, vx));
            view.setScaleY(evaluateFloat(fraction, 1, vy));
            view.setAlpha(1 - fraction);
            rootView.setBackgroundColor(evaluateArgb(fraction, Color.BLACK, Color.TRANSPARENT));
        });
        addOutListener(valueAnimator);
        valueAnimator.setDuration(ANIMATE_DURATION);
        valueAnimator.start();
    }

    /** 计算图片的宽高 */
    private void computeImageWidthAndHeight(ImageView imageView) {

        // 获取真实大小
        Drawable drawable = imageView.getDrawable();
        int intrinsicHeight = drawable.getIntrinsicHeight();
        int intrinsicWidth = drawable.getIntrinsicWidth();
        // 计算出与屏幕的比例，用于比较以宽的比例为准还是高的比例为准，因为很多时候不是高度没充满，就是宽度没充满
        float h = screenHeight * 1.0f / intrinsicHeight;
        float w = screenWidth * 1.0f / intrinsicWidth;
        if (h > w) {
            h = w;
        } else {
            w = h;
        }

        // 得出当宽高至少有一个充满的时候图片对应的宽高
        imageHeight = (int) (intrinsicHeight * h);
        imageWidth = (int) (intrinsicWidth * w);
    }

    /** 进场动画过程监听 */
    private void addIntoListener(ValueAnimator valueAnimator) {
        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                rootView.setBackgroundColor(0x0);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }
        });
    }

    /** 退场动画过程监听 */
    private void addOutListener(ValueAnimator valueAnimator) {
        valueAnimator.addListener(new Animator.AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animation) {
                rootView.setBackgroundColor(0x0);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                finish();
                overridePendingTransition(0, 0);
            }

            @Override
            public void onAnimationCancel(Animator animation) {
            }

            @Override
            public void onAnimationRepeat(Animator animation) {
            }
        });
    }

    /** Integer 估值器 */
    public Integer evaluateInt(float fraction, Integer startValue, Integer endValue) {
        int startInt = startValue;
        return (int) (startInt + fraction * (endValue - startInt));
    }

    /** Float 估值器 */
    public Float evaluateFloat(float fraction, Number startValue, Number endValue) {
        float startFloat = startValue.floatValue();
        return startFloat + fraction * (endValue.floatValue() - startFloat);
    }

    /** Argb 估值器 */
    public int evaluateArgb(float fraction, int startValue, int endValue) {
        int startA = (startValue >> 24) & 0xff;
        int startR = (startValue >> 16) & 0xff;
        int startG = (startValue >> 8) & 0xff;
        int startB = startValue & 0xff;

        int endA = (endValue >> 24) & 0xff;
        int endR = (endValue >> 16) & 0xff;
        int endG = (endValue >> 8) & 0xff;
        int endB = endValue & 0xff;

        return (startA + (int) (fraction * (endA - startA))) << 24
                | (startR + (int) (fraction * (endR - startR))) << 16
                | (startG + (int) (fraction * (endG - startG))) << 8
                | (startB + (int) (fraction * (endB - startB)));
    }
}
